package de.pass.ch.junit;

import static org.junit.Assert.*;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Random;
import java.util.Set;

import org.junit.Test;

import de.pass.ch.assign.Assignment;
import de.pass.ch.assign.AssignmentFactory;
import de.pass.ch.dijkstra.DijkstraSearchCH;
import de.pass.ch.graph.Path;
import de.pass.ch.graph.SearchGraph;
import de.pass.ch.graph.edge.Edge;
import de.pass.ch.pt.IStreetProfile;
import de.pass.ch.pt.StreetProfile;
import de.pass.ch.util.Constants;

public class TestSearchGraph {

	public String DIR = "D:\\";

	@Test
	public void testSearchGraph() {

		DecimalFormat format = new DecimalFormat(",##0.00");

		FileInputStream fIn = null;

		SearchGraph sgr = new SearchGraph(null, null);

		try {

			fIn = new FileInputStream(DIR + "searchGraph.dach_nio.sgr");
			sgr.deserializeFast(fIn);
			fIn.close();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (fIn != null)
					fIn.close();
			} catch (Exception e) {
			}
		}

		assertNotNull(sgr);

		int[] nodemapping = readNodeMapping();

		// int[] testNodes = readTestNodes();
		int[] testNodes = getRandomUSS(100, nodemapping.length);
		// int[] testNodes = { 227071, 5461272 };

		IStreetProfile streetProfile = StreetProfile
				.getInstance(StreetProfile.DEFAULT_PROFILE);
		AssignmentFactory factory = new AssignmentFactory(DIR
				+ "assignmentDACH.ass");
		int mode = Constants.DISTANCE_OPT;

		DijkstraSearchCH dijkstra = new DijkstraSearchCH(sgr, DIR
				+ "nodemapping.ser", streetProfile, factory, mode);

		int distance = 0;
		int fails = 0;
		int longDistances = 0;

		int k = 0;

		StringBuilder sBuilder = new StringBuilder();

		int noOfNodes = sgr.noOfNodes();

		factory.loadAssignments(testNodes, nodemapping, noOfNodes,
				streetProfile, mode);

		System.out.println("search-test .....");

		sBuilder.append("source;target;distance\n");

		long checksum = 0;

		long time = System.currentTimeMillis();

		for (int i = 0; i < testNodes.length; i++) {
			for (int j = 0; j < testNodes.length; j++) {
				if (i != j) {
					k++;
					distance = dijkstra.bidirSearch(testNodes[i], testNodes[j]);
					checksum += distance;

					if (distance > 1000000)
						if (distance > 5000000)
							fails++;
						else
							longDistances++;

					sBuilder.append(testNodes[i] + ";" + testNodes[j] + ";"
							+ distance + "\n");

					// Path path = dijkstra.pathTo(0, -1, true);
					// printPath(path, nodemapping);
					// int pathDist = 0;
					// for (Edge edge : path.edges) {
					// pathDist += edge.getWeight();
					// }
					//
					// if (!(nodemapping[testNodes[i]] < noOfNodes &&
					// nodemapping[testNodes[j]] < noOfNodes)) {
					// if (nodemapping[testNodes[i]] >= noOfNodes) {
					// Assignment[] ass = factory.getAssignments(
					// nodemapping[testNodes[i]], noOfNodes,
					// streetProfile, mode);
					// if (ass[0].getAssignedID() == path.startNode) {
					// pathDist += ass[0].getWeight();
					// path.startNode = nodemapping[ass[0]
					// .getDeletedID()];
					// } else {
					// pathDist += ass[1].getWeight();
					// path.startNode = nodemapping[ass[0]
					// .getDeletedID()];
					// }
					// }
					// if (nodemapping[testNodes[j]] >= noOfNodes) {
					// Assignment[] ass = factory.getAssignments(
					// nodemapping[testNodes[j]], noOfNodes,
					// streetProfile, mode);
					// if (ass[0].getAssignedID() == path.targetNode) {
					// pathDist += ass[0].getWeight();
					// path.targetNode = nodemapping[ass[0]
					// .getDeletedID()];
					// } else {
					// pathDist += ass[1].getWeight();
					// path.targetNode = nodemapping[ass[1]
					// .getDeletedID()];
					// }
					// }
					// }
					//
					// assertEquals(nodemapping[testNodes[i]], path.startNode);
					// assertEquals(nodemapping[testNodes[j]], path.targetNode);
					// assertEquals(distance, pathDist);

					dijkstra.clear();
				}
			}
		}

		PrintWriter writer = null;

		try {

			if (!"".equals(sBuilder.toString().trim())) {
				writer = new PrintWriter(DIR + "logDistCH.eco.txt");
				writer.write(sBuilder.toString());
				writer.flush();
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				if (writer != null)
					writer.close();
			} catch (Exception e) {
			}
		}

		time = System.currentTimeMillis() - time;

		System.out.println("bidirSearch took " + time + " ms");
		System.out.println("time/distance: "
				+ format.format((double) time / (double) k) + " ms");
		System.out.println(fails + " fails");
		System.out.println(longDistances + " longDistances");
		System.out.println("checksum: " + checksum);

		System.out.println(testNodes[testNodes.length - 1] + " -> "
				+ testNodes[testNodes.length - 2] + " : " + distance);

		System.out.println("#nodes: " + sgr.noOfNodes());
		System.out.println("#edges: " + sgr.noOfEdges());

	}

	protected void printPath(Path path, int[] nodemapping) {

		System.out.println();

		int i = 0;
		for (Edge e : path.edges) {
			System.out.println(++i + ":\t" + e);
		}

		System.out.println();

	}

	protected int[] getRandomUSS(int n, int nodes) {
		Random r = new Random();

		Set<Integer> ussSet = new LinkedHashSet<Integer>();
		int[] uss = new int[n];

		int k = 0;
		for (int i = 0; i < n; i++) {
			k = r.nextInt(nodes) + 1;
			while (!ussSet.add(k)) {
				k = r.nextInt(nodes) + 1;
			}
			uss[i] = k;
		}

		ussSet = null;
		r = null;

		Arrays.sort(uss);
		ObjectOutputStream oOut = null;
		try {

			oOut = new ObjectOutputStream(new FileOutputStream(DIR
					+ "testNodes.ser"));
			oOut.writeObject(uss);

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (oOut != null)
					oOut.close();
			} catch (Exception e) {
			}
		}
		return uss;
	}

	protected int[] readTestNodes() {
		ObjectInputStream oIn = null;
		int[] nodes = null;
		try {

			oIn = new ObjectInputStream(new FileInputStream(DIR
					+ "testNodes.ser"));
			nodes = (int[]) oIn.readObject();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				if (oIn != null)
					oIn.close();
			} catch (Exception e) {
			}
		}
		return nodes;
	}

	protected int[] readNodeMapping() {
		ObjectInputStream oIn = null;
		int[] nodes = null;
		try {

			oIn = new ObjectInputStream(new FileInputStream(DIR
					+ "nodemapping.ser"));
			nodes = (int[]) oIn.readObject();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				if (oIn != null)
					oIn.close();
			} catch (Exception e) {
			}
		}
		return nodes;
	}

}
